<?php

namespace App\Trip\Wechat\Pay\PayRes;

use App\Trip\Payment\PayResultInterface;
use App\Trip\Wechat\Pay\Application;
use App\Trip\Wechat\Pay\WechatPay;
use Carbon\Carbon;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;

class PayResult implements PayResultInterface
{
    private mixed $result;

    public function __construct($result)
    {
        $this->setResult($result);
    }

    private function setResult($result): void
    {
        if (is_string($result)) {
            $result = json_decode($result, true);
        }
        $this->result = $result;
    }

    public function getApplication()
    {
        // TODO: Implement getApplication() method.
        return $this->getWechatApplication();
    }

    /**
     * 微信支付实例
     *
     * @throws InvalidArgumentException
     */
    public function getWechatApplication(): Application
    {
        $wechatPay = new WechatPay(['mchid' => $this->getMchId()]);
        return $wechatPay->getApplication();
    }

    /**
     * 商户号
     *
     * @return string
     */
    public function getMchId(): string
    {
        return $this->mchid;
    }

    /**
     * 小程序id
     *
     * @return string
     */
    public function getAppId(): string
    {
        return $this->appid;
    }

    /**
     * 微信单号
     *
     * @return mixed
     */
    public function getTransactionId(): string
    {
        return $this->transaction_id;
    }

    public function isSuccess(): bool
    {
        return $this->getTradeState() == "SUCCESS";
    }

    /**
     * SUCCESS：支付成功
     * REFUND：转入退款
     * NOTPAY：未支付
     * CLOSED：已关闭
     * REVOKED：已撤销（付款码支付）
     * USERPAYING：用户支付中（付款码支付）
     * PAYERROR：支付失败(其他原因，如银行返回失败)
     *
     * @return mixed
     */
    public function getTradeState()
    {
        return $this->trade_state;
    }

    /**
     * 失败发起退款逻辑
     *
     * @return mixed
     * @throws InvalidArgumentException
     * @throws InvalidConfigException
     */
    public function fail2Refund(string $reason = ""): mixed
    {
        $notify_url   = URL::to("/api/payment/wechat/callback");
        $app          = $this->getWechatApplication();
        $api          = $app->getClient();
        $out_trade_no = $this->getOutTradeNo();
        $pay_fee      = $this->getTotalFee();
        $param        = [
            'out_trade_no'  => $out_trade_no,
            'out_refund_no' => "FR".$out_trade_no,
            'reason'        => $reason ?: "订单不存在",
            'notify_url'    => $notify_url,
            'amount'        => [
                'refund'   => $pay_fee,
                'total'    => $pay_fee,
                'currency' => 'CNY',
            ],
        ];
        Log::info(json_encode(['fail2Refund 退款参数' => $param], JSON_UNESCAPED_UNICODE));
        $refundResp = $api->postJson("v3/refund/domestic/refunds", $param)->toArray();
        Log::info($refundResp);
        return $refundResp;
    }

    /**
     * 系统单号
     *
     * @return mixed
     */
    public function getOutTradeNo(): string
    {
        return $this->out_trade_no;
    }

    public function getTotalFee(): int
    {
        return $this->amount['total'];
    }

    public function getTradeStateDesc()
    {
        return $this->trade_state_desc ?? "";
    }

    public function getSuccessAt(): string
    {
        return Carbon::parse($this->success_time)->toDateTimeString();
    }

    /**
     * 自定义数据
     *
     * @return string
     */
    public function getAttach(): string
    {
        return $this->attach;
    }

    public function getPayAmount(): float
    {
        return bcdiv($this->getTotalFee(), 100, 2);
    }

    public function getOpenId(): string
    {
        return $this->payer['openid'];
    }

    /**
     * @throws Exception
     */
    public function __get($name)
    {
        if (isset($this->result[$name])) {
            return $this->result[$name];
        }

        if (isset($this->result["code"]) && isset($this->result["message"])) {
            throw new Exception("{$this->result["message"]}", 404);
        }
        throw new Exception("属性：{$name}不存在");
    }

    public function __toString(): string
    {
        return json_encode($this->result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '';
    }
}